


#include "autoconfig.h"


#ifndef CONFIG_PLATFORM_OS


#include "qe_service.h"
#include "qe_platform.h"



/**
 * strcpy - Copy a %NUL terminated string
 * @dest: Where to copy the string to
 * @src: Where to copy the string from
 */
char *qe_strcpy(char *dest, const char *src)
{
	char *tmp = dest;

	while ((*dest++ = *src++) != '\0')
		/* nothing */;
	return tmp;
}

/**
 * strncpy - Copy a length-limited, %NUL-terminated string
 * @dest: Where to copy the string to
 * @src: Where to copy the string from
 * @count: The maximum number of bytes to copy
 *
 * Note that unlike userspace strncpy, this does not %NUL-pad the buffer.
 * However, the result is not %NUL-terminated if the source exceeds
 * @count bytes.
 */
char *qe_strncpy(char *dest, const char *src, qe_size_t count)
{
	char *tmp = dest;

	while (count-- && (*dest++ = *src++) != '\0')
		/* nothing */;

	return tmp;
}

qe_size_t qe_strlcpy(char *dest, const char *src, qe_size_t size)
{
	qe_size_t ret = qe_strlen(src);

	if (size) {
		qe_size_t len = (ret >= size) ? size - 1 : ret;
		qe_memcpy(dest, (void *)src, len);
		dest[len] = '\0';
	}
	return ret;
}

/**
 * strcat - Append one %NUL-terminated string to another
 * @dest: The string to be appended to
 * @src: The string to append to it
 */
char *qe_strcat(char *dest, const char *src)
{
	char *tmp = dest;

	while (*dest)
		dest++;
	while ((*dest++ = *src++) != '\0')
		;

	return tmp;
}

/**
 * strncat - Append a length-limited, %NUL-terminated string to another
 * @dest: The string to be appended to
 * @src: The string to append to it
 * @count: The maximum numbers of bytes to copy
 *
 * Note that in contrast to strncpy, strncat ensures the result is
 * terminated.
 */
char *qe_strncat(char *dest, const char *src, qe_size_t count)
{
	char *tmp = dest;

	if (count) {
		while (*dest)
			dest++;
		while ((*dest++ = *src++)) {
			if (--count == 0) {
				*dest = '\0';
				break;
			}
		}
	}

	return tmp;
}

/**
 * strcmp - Compare two strings
 * @cs: One string
 * @ct: Another string
 */
int qe_strcmp(const char *cs, const char *ct)
{
	register signed char __res;

	while (1) {
		if ((__res = *cs - *ct++) != 0 || !*cs++)
			break;
	}

	return __res;
}

/**
 * strncmp - Compare two length-limited strings
 * @cs: One string
 * @ct: Another string
 * @count: The maximum number of bytes to compare
 */
int qe_strncmp(const char *cs, const char *ct, qe_size_t count)
{
	register signed char __res = 0;

	while (count) {
		if ((__res = *cs - *ct++) != 0 || !*cs++)
			break;
		count--;
	}

	return __res;
}

/**
 * strchr - Find the first occurrence of a character in a string
 * @s: The string to be searched
 * @c: The character to search for
 */
char *qe_strchr(const char *s, int c)
{
	for(; *s != (char) c; ++s)
		if (*s == '\0')
			return QE_NULL;
	return (char *) s;
}

const char *qe_strchrnul(const char *s, int c)
{
	for (; *s != (char)c; ++s)
		if (*s == '\0')
			break;
	return s;
}

/**
 * strrchr - Find the last occurrence of a character in a string
 * @s: The string to be searched
 * @c: The character to search for
 */
char *qe_strrchr(const char *s, int c)
{
    const char *p = s + qe_strlen(s);
    do {
    if (*p == (char)c)
        return (char *)p;
    } while (--p >= s);
    return QE_NULL;
}

/**
 * strlen - Find the length of a string
 * @s: The string to be sized
 */
qe_size_t qe_strlen(const char *s)
{
	const char *sc;

	for (sc = s; *sc != '\0'; ++sc)
		/* nothing */;
	return sc - s;
}

/**
 * strnlen - Find the length of a length-limited string
 * @s: The string to be sized
 * @count: The maximum number of bytes to search
 */
qe_size_t qe_strnlen(const char *s, qe_size_t count)
{
	const char *sc;

	for (sc = s; count-- && *sc != '\0'; ++sc)
		/* nothing */;
	return sc - s;
}

/**
 * strcspn - Calculate the length of the initial substring of @s which does
 * not contain letters in @reject
 * @s: The string to be searched
 * @reject: The string to avoid
 */
qe_size_t qe_strcspn(const char *s, const char *reject)
{
	const char *p;
	const char *r;
	qe_size_t count = 0;

	for (p = s; *p != '\0'; ++p) {
		for (r = reject; *r != '\0'; ++r) {
			if (*p == *r)
				return count;
		}
		++count;
	}
	return count;
}

char *qe_strdup(const char *s)
{
	char *new;

	if ((s == QE_NULL)	||
	    ((new = qe_malloc(qe_strlen(s) + 1)) == QE_NULL) ) {
		return QE_NULL;
	}

	qe_strcpy(new, s);
	return new;
}

char *qe_strndup(const char *s, qe_size_t n)
{
	qe_size_t len;
	char *new;

	if (s == QE_NULL)
		return QE_NULL;

	len = qe_strlen(s);

	if (n < len)
		len = n;

	new = qe_malloc(len + 1);
	if (new == QE_NULL)
		return QE_NULL;

	qe_strncpy(new, s, len);
	new[len] = '\0';

	return new;
}

/**
 * strspn - Calculate the length of the initial substring of @s which only
 *	contain letters in @accept
 * @s: The string to be searched
 * @accept: The string to search for
 */
qe_size_t qe_strspn(const char *s, const char *accept)
{
	const char *p;
	const char *a;
	qe_size_t count = 0;

	for (p = s; *p != '\0'; ++p) {
		for (a = accept; *a != '\0'; ++a) {
			if (*p == *a)
				break;
		}
		if (*a == '\0')
			return count;
		++count;
	}

	return count;
}

/**
 * strpbrk - Find the first occurrence of a set of characters
 * @cs: The string to be searched
 * @ct: The characters to search for
 */
char *qe_strpbrk(const char *cs, const char *ct)
{
	const char *sc1, *sc2;

	for (sc1 = cs; *sc1 != '\0'; ++sc1) {
		for (sc2 = ct; *sc2 != '\0'; ++sc2) {
			if (*sc1 == *sc2)
				return (char *)sc1;
		}
	}
	return QE_NULL;
}

char * ___strtok;

/**
 * strtok - Split a string into tokens
 * @s: The string to be searched
 * @ct: The characters to search for
 *
 * WARNING: strtok is deprecated, use strsep instead.
 */
char *qe_strtok(char *s, const char *ct)
{
	char *sbegin, *send;

	sbegin  = s ? s : ___strtok;
	if (!sbegin) {
		return QE_NULL;
	}
	sbegin += qe_strspn(sbegin,ct);
	if (*sbegin == '\0') {
		___strtok = QE_NULL;
		return QE_NULL;
	}
	send = qe_strpbrk( sbegin, ct);
	if (send && *send != '\0')
		*send++ = '\0';
	___strtok = send;
	return (sbegin);
}

/**
 * strsep - Split a string into tokens
 * @s: The string to be searched
 * @ct: The characters to search for
 *
 * strsep() updates @s to point after the token, ready for the next call.
 *
 * It returns empty tokens, too, behaving exactly like the libc function
 * of that name. In fact, it was stolen from glibc2 and de-fancy-fied.
 * Same semantics, slimmer shape. ;)
 */
char *qe_strsep(char **s, const char *ct)
{
	char *sbegin = *s, *end;

	if (sbegin == QE_NULL)
		return QE_NULL;

	end = qe_strpbrk(sbegin, ct);
	if (end)
		*end++ = '\0';
	*s = end;

	return sbegin;
}

/**
 * strswab - swap adjacent even and odd bytes in %NUL-terminated string
 * s: address of the string
 *
 * returns the address of the swapped string or NULL on error. If
 * string length is odd, last byte is untouched.
 */
char *qe_strswab(const char *s)
{
	char *p, *q;

	if ((QE_NULL == s) || ('\0' == *s)) {
		return (QE_NULL);
	}

	for (p=(char *)s, q=p+1; (*p != '\0') && (*q != '\0'); p+=2, q+=2) {
		char  tmp;

		tmp = *p;
		*p  = *q;
		*q  = tmp;
	}

	return (char *) s;
}

/**
 * memset - Fill a region of memory with the given value
 * @s: Pointer to the start of the area.
 * @c: The byte to fill the area with
 * @count: The size of the area.
 *
 */
void *qe_memset(void *s, int c, qe_size_t count)
{
#if (CONFIG_QE_TINY == 1)
	char *xs = (char *)s;
	while (count--)
		*xs++ = c;
	return s;
#else
#define LBLOCKSIZE		(sizeof(long))
#define UNALIGNED(x)	((long)x & (LBLOCKSIZE-1))
#define TOO_SMALL(len)  ((len) < LBLOCKSIZE)

	unsigned int i;
	char *m = (char *)s;
	unsigned long buffer;
	unsigned long *aligned_addr;
	unsigned int d = c & 0xff;	/* To avoid sign extension, copy C to an unsigned variable */

	if (!TOO_SMALL(count) && !UNALIGNED(s)) {

		/* If we get this far, we know that count is large and s is word-aligned. */
		aligned_addr = (unsigned long *)s;

		/* Store d into each char sized location in buffer so that
         * we can set large blocks quickly.
         */
		if (LBLOCKSIZE == 4) {
			buffer = (d << 8) | d;
			buffer |= (buffer << 16);
		} else {
			buffer = 0;
			for (i = 0; i < LBLOCKSIZE; i ++)
				buffer = (buffer << 8) | d;
		}

		while (count >= LBLOCKSIZE * 4) {
			*aligned_addr++ = buffer;
			*aligned_addr++ = buffer;
			*aligned_addr++ = buffer;
			*aligned_addr++ = buffer;
			count -= 4 * LBLOCKSIZE;
		}

		while (count >= LBLOCKSIZE) {
            *aligned_addr++ = buffer;
            count -= LBLOCKSIZE;
        }

		/* Pick up the remainder with a bytewise loop. */
		m = (char *)aligned_addr;
	}

	while (count--)
		*m++ = (char)d;
	return s;
#undef LBLOCKSIZE
#undef UNALIGNED
#undef TOO_SMALL
#endif
}

/**
 * This function will copy memory content from source address to destination
 * address.
 *
 * @dst   : the address of destination memory
 * @src   : the address of source memory
 * @count : the copied length
 *
 * @return the address of destination memory
 */
void *qe_memcpy(void *dst, void *src, qe_size_t count)
{
#if (CONFIG_QE_TINY == 1)
	char *tmp = (char *)dst, *s = (char *)src;
	qe_ubase_t len;
	if (tmp <= s || tmp > (s + count)) {
		while (count--)
			*tmp ++ = *s ++;
	} else {
		for (len = count; len > 0; len --)
			tmp[len - 1] = s[len - 1];
	}
	return dst;
#else
#define UNALIGNED(X, Y) \
    (((long)X & (sizeof (long) - 1)) | ((long)Y & (sizeof (long) - 1)))
#define BIGBLOCKSIZE    (sizeof (long) << 2)
#define LITTLEBLOCKSIZE (sizeof (long))
#define TOO_SMALL(LEN)  ((LEN) < BIGBLOCKSIZE)
	char *dst_ptr = (char *)dst;
    char *src_ptr = (char *)src;
    long *aligned_dst;
    long *aligned_src;
    int len = count;

	/* If the size is small, or either SRC or DST is unaligned,
	then punt into the byte copy loop.	This should be rare. */
	if (!TOO_SMALL((unsigned int)len) && !UNALIGNED(src_ptr, dst_ptr)) 
	{
		aligned_dst = (long *)dst_ptr;
		aligned_src = (long *)src_ptr;
		
		/* Copy 4X long words at a time if possible. */
		while ((unsigned int)len >= (unsigned int)BIGBLOCKSIZE)
		{
            *aligned_dst++ = *aligned_src++;
            *aligned_dst++ = *aligned_src++;
            *aligned_dst++ = *aligned_src++;
            *aligned_dst++ = *aligned_src++;
            len -= BIGBLOCKSIZE;
		}

		/* Copy one long word at a time if possible. */
        while ((unsigned int)len >= LITTLEBLOCKSIZE)
        {
            *aligned_dst++ = *aligned_src++;
            len -= LITTLEBLOCKSIZE;
        }

		/* Pick up any residual with a byte copier. */
		dst_ptr = (char *)aligned_dst;
		src_ptr = (char *)aligned_src;
	}

	while (len--)
		*dst_ptr++ = *src_ptr++;

	return dst;
#undef UNALIGNED
#undef BIGBLOCKSIZE
#undef LITTLEBLOCKSIZE
#undef TOO_SMALL
#endif
}

/**
 * memmove - Copy one area of memory to another
 * @dest: Where to copy to
 * @src: Where to copy from
 * @count: The size of the area.
 */
void *qe_memmove(void *dest, const void *src, qe_size_t count)
{
	char *tmp, *s;

	if (dest <= src) {
		qe_memcpy(dest, (void *)src, count);
	} else {
		tmp = (char *) dest + count;
		s = (char *) src + count;
		while (count--)
			*--tmp = *--s;
		}

	return dest;
}

/**
 * memcmp - Compare two areas of memory
 * @cs: One area of memory
 * @ct: Another area of memory
 * @count: The size of the area.
 */
int qe_memcmp(const void *cs,const void *ct, qe_size_t count)
{
	const unsigned char *su1, *su2;
	int res = 0;

	for( su1 = cs, su2 = ct; 0 < count; ++su1, ++su2, count--)
		if ((res = *su1 - *su2) != 0)
			break;
	return res;
}

/**
 * memscan - Find a character in an area of memory.
 * @addr: The memory area
 * @c: The byte to search for
 * @size: The size of the area.
 *
 * returns the address of the first occurrence of @c, or 1 byte past
 * the area if @c is not found
 */
void *qe_memscan(void *addr, int c, qe_size_t size)
{
	unsigned char * p = (unsigned char *) addr;

	while (size) {
		if (*p == c)
			return (void *) p;
		p++;
		size--;
	}
	return (void *) p;
}

/**
 * strstr - Find the first substring in a %NUL terminated string
 * @s1: The string to be searched
 * @s2: The string to search for
 */
char *qe_strstr(const char *s1, const char *s2)
{
	int l1, l2;

	l2 = qe_strlen(s2);
	if (!l2)
		return (char *) s1;
	l1 = qe_strlen(s1);
	while (l1 >= l2) {
		l1--;
		if (!qe_memcmp(s1,s2,l2))
			return (char *) s1;
		s1++;
	}
	return QE_NULL;
}

/**
 * memchr - Find a character in an area of memory.
 * @s: The memory area
 * @c: The byte to search for
 * @n: The size of the area.
 *
 * returns the address of the first occurrence of @c, or %NULL
 * if @c is not found
 */
void *qe_memchr(const void *s, int c, qe_size_t n)
{
	const unsigned char *p = s;
	while (n-- != 0) {
		if ((unsigned char)c == *p++) {
			return (void *)(p-1);
		}
	}
	return QE_NULL;
}

#if (CONFIG_PRINTF_LONGLONG == 1)
static inline int divide(long long *n, int base)
{
    int res;

    /* optimized for processor which does not support divide instructions. */
    if (base == 10)
    {
        res = (int)(((unsigned long long)*n) % 10U);
        *n = (long long)(((unsigned long long)*n) / 10U);
    }
    else
    {
        res = (int)(((unsigned long long)*n) % 16U);
        *n = (long long)(((unsigned long long)*n) / 16U);
    }

    return res;
}
#else
static inline int divide(long *n, int base)
{
    int res;

    /* optimized for processor which does not support divide instructions. */
    if (base == 10)
    {
        res = (int)(((unsigned long)*n) % 10U);
        *n = (long)(((unsigned long)*n) / 10U);
    }
    else
    {
        res = (int)(((unsigned long)*n) % 16U);
        *n = (long)(((unsigned long)*n) / 16U);
    }

    return res;
}
#endif

#define _ISDIGIT(c)  ((unsigned)((c) - '0') < 10)

static inline int skip_atoi(const char **s)
{
    register int i = 0;
    while (_ISDIGIT(**s))
        i = i * 10 + *((*s)++) - '0';

    return i;
}

#define ZEROPAD     (1 << 0)    /* pad with zero */
#define SIGN        (1 << 1)    /* unsigned/signed long */
#define PLUS        (1 << 2)    /* show plus */
#define SPACE       (1 << 3)    /* space if plus */
#define LEFT        (1 << 4)    /* left justified */
#define SPECIAL     (1 << 5)    /* 0x */
#define LARGE       (1 << 6)    /* use 'ABCDEF' instead of 'abcdef' */

#if (CONFIG_PRINTF_PRECISION == 1)
static char *print_number(char *buf,
                          char *end,
#if (CONFIG_PRINTF_LONGLONG == 1)
                          long long  num,
#else
                          long  num,
#endif
                          int   base,
                          int   s,
                          int   precision,
                          int   type)
#else
static char *print_number(char *buf,
                          char *end,
#if (CONFIG_PRINTF_LONGLONG == 1)
                          long long  num,
#else
                          long  num,
#endif
                          int   base,
                          int   s,
                          int   type)
#endif
{
    char c, sign;
#if (CONFIG_PRINTF_LONGLONG == 1)
    char tmp[32];
#else
    char tmp[16];
#endif
#if (CONFIG_PRINTF_PRECISION == 1)
    int precision_bak = precision;
#else
    int precision_bak = 0;
#endif
    const char *digits;
    static const char small_digits[] = "0123456789abcdef";
    static const char large_digits[] = "0123456789ABCDEF";
    register int i;
    register int size;

    size = s;

    digits = (type & LARGE) ? large_digits : small_digits;
    if (type & LEFT)
        type &= ~ZEROPAD;

    c = (type & ZEROPAD) ? '0' : ' ';

    /* get sign */
    sign = 0;
    if (type & SIGN)
    {
        if (num < 0)
        {
            sign = '-';
            num = -num;
        }
        else if (type & PLUS)
            sign = '+';
        else if (type & SPACE)
            sign = ' ';
    }

#if (CONFIG_PRINTF_SPECIAL == 1)
    if (type & SPECIAL)
    {
        if (base == 16)
            size -= 2;
        else if (base == 8)
            size--;
    }
#endif

    i = 0;
    if (num == 0)
        tmp[i++] = '0';
    else
    {
        while (num != 0)
            tmp[i++] = digits[divide(&num, base)];
    }

#if (QE_PRINTF_PRECISION == 1)
    if (i > precision)
        precision = i;
    size -= precision;
#else
    size -= i;
#endif

    if (!(type & (ZEROPAD | LEFT)))
    {
        if ((sign) && (size > 0))
            size--;

        while (size-- > 0)
        {
            if (buf < end)
                *buf = ' ';
            ++ buf;
        }
    }

    if (sign)
    {
        if (buf < end)
        {
            *buf = sign;
        }
        -- size;
        ++ buf;
    }

#if (CONFIG_PRINTF_SPECIAL == 1)
    if (type & SPECIAL)
    {
        if (base == 8)
        {
            if (buf < end)
                *buf = '0';
            ++ buf;
        }
        else if (base == 16)
        {
            if (buf < end)
                *buf = '0';
            ++ buf;
            if (buf < end)
            {
                *buf = type & LARGE ? 'X' : 'x';
            }
            ++ buf;
        }
    }
#endif

    /* no align to the left */
    if (!(type & LEFT))
    {
        while (size-- > 0)
        {
            if (buf < end)
                *buf = c;
            ++ buf;
        }
    }

#if (CONFIG_PRINTF_PRECISION == 1)
    while (i < precision--)
    {
        if (buf < end)
            *buf = '0';
        ++ buf;
    }
#endif

    /* put number in the temporary buffer */
    while (i-- > 0 && (precision_bak != 0))
    {
        if (buf < end)
            *buf = tmp[i];
        ++ buf;
    }

    while (size-- > 0)
    {
        if (buf < end)
            *buf = ' ';
        ++ buf;
    }

    return buf;
}

int qe_vsnprintf(char *buf, qe_size_t size, const char *fmt, va_list args)
{
#if (CONFIG_PRINTF_LONGLONG == 1)
    unsigned long long num;
#else
    qe_u32 num;
#endif
    int i, len;
    char *str, *end, c;
    const char *s;

    qe_u8 base;            /* the base of number */
    qe_u16 flags;           /* flags to print number */
    qe_u8 qualifier;       /* 'h', 'l', or 'L' for integer fields */
    qe_s32 field_width;     /* width of output field */

#if (CONFIG_PRINTF_PRECISION == 1)
    int precision;      /* min. # of digits for integers and max for a string */
#endif

    str = buf;
    end = buf + size;

    /* Make sure end is always >= buf */
    if (end < buf)
    {
        end  = ((char *) - 1);
        size = end - buf;
    }

    for (; *fmt ; ++fmt)
    {
        if (*fmt != '%')
        {
            if (str < end)
                *str = *fmt;
            ++ str;
            continue;
        }

        /* process flags */
        flags = 0;

        while (1)
        {
            /* skips the first '%' also */
            ++ fmt;
            if (*fmt == '-') flags |= LEFT;
            else if (*fmt == '+') flags |= PLUS;
            else if (*fmt == ' ') flags |= SPACE;
            else if (*fmt == '#') flags |= SPECIAL;
            else if (*fmt == '0') flags |= ZEROPAD;
            else break;
        }

        /* get field width */
        field_width = -1;
        if (_ISDIGIT(*fmt)) field_width = skip_atoi(&fmt);
        else if (*fmt == '*')
        {
            ++ fmt;
            /* it's the next argument */
            field_width = va_arg(args, int);
            if (field_width < 0)
            {
                field_width = -field_width;
                flags |= LEFT;
            }
        }

#if (CONFIG_PRINTF_PRECISION == 1)
        /* get the precision */
        precision = -1;
        if (*fmt == '.')
        {
            ++ fmt;
            if (_ISDIGIT(*fmt)) precision = skip_atoi(&fmt);
            else if (*fmt == '*')
            {
                ++ fmt;
                /* it's the next argument */
                precision = va_arg(args, int);
            }
            if (precision < 0) precision = 0;
        }
#endif
        /* get the conversion qualifier */
        qualifier = 0;
#if (CONFIG_PRINTF_LONGLONG == 1)
        if (*fmt == 'h' || *fmt == 'l' || *fmt == 'L')
#else
        if (*fmt == 'h' || *fmt == 'l')
#endif
        {
            qualifier = *fmt;
            ++ fmt;
#if (CONFIG_PRINTF_LONGLONG == 1)
            if (qualifier == 'l' && *fmt == 'l')
            {
                qualifier = 'L';
                ++ fmt;
            }
#endif
        }

        /* the default base */
        base = 10;

        switch (*fmt)
        {
        case 'c':
            if (!(flags & LEFT))
            {
                while (--field_width > 0)
                {
                    if (str < end) *str = ' ';
                    ++ str;
                }
            }

            /* get character */
            c = (qe_u8)va_arg(args, int);
            if (str < end) *str = c;
            ++ str;

            /* put width */
            while (--field_width > 0)
            {
                if (str < end) *str = ' ';
                ++ str;
            }
            continue;

        case 's':
            s = va_arg(args, char *);
            if (!s) s = "(NULL)";

            len = qe_strlen(s);
#if (CONFIG_PRINTF_PRECISION == 1)
            if (precision > 0 && len > precision) len = precision;
#endif

            if (!(flags & LEFT))
            {
                while (len < field_width--)
                {
                    if (str < end) *str = ' ';
                    ++ str;
                }
            }

            for (i = 0; i < len; ++i)
            {
                if (str < end) *str = *s;
                ++ str;
                ++ s;
            }

            while (len < field_width--)
            {
                if (str < end) *str = ' ';
                ++ str;
            }
            continue;

        case 'p':
            if (field_width == -1)
            {
                field_width = sizeof(void *) << 1;
                flags |= ZEROPAD;
            }
#if (CONFIG_PRINTF_PRECISION == 1)
            str = print_number(str, end,
                               (long)va_arg(args, void *),
                               16, field_width, precision, flags);
#else
            str = print_number(str, end,
                               (long)va_arg(args, void *),
                               16, field_width, flags);
#endif
            continue;

        case '%':
            if (str < end) *str = '%';
            ++ str;
            continue;

        /* integer number formats - set up the flags and "break" */
        case 'o':
            base = 8;
            break;

        case 'X':
            flags |= LARGE;
        case 'x':
            base = 16;
            break;

        case 'd':
        case 'i':
            flags |= SIGN;
        case 'u':
            break;

        default:
            if (str < end) *str = '%';
            ++ str;

            if (*fmt)
            {
                if (str < end) *str = *fmt;
                ++ str;
            }
            else
            {
                -- fmt;
            }
            continue;
        }

#if (CONFIG_PRINTF_LONGLONG == 1)
        if (qualifier == 'L') num = va_arg(args, long long);
        else if (qualifier == 'l')
#else
        if (qualifier == 'l')
#endif
        {
            num = va_arg(args, qe_u32);
            if (flags & SIGN) num = (qe_s32)num;
        }
        else if (qualifier == 'h')
        {
            num = (qe_u16)va_arg(args, qe_s32);
            if (flags & SIGN) num = (qe_s16)num;
        }
        else
        {
            num = va_arg(args, qe_u32);
            if (flags & SIGN) num = (qe_s32)num;
        }
#if (CONFIG_PRINTF_PRECISION == 1)
        str = print_number(str, end, num, base, field_width, precision, flags);
#else
        str = print_number(str, end, num, base, field_width, flags);
#endif
    }

    if (size > 0)
    {
        if (str < end) *str = '\0';
        else
        {
            end[-1] = '\0';
        }
    }

    /* the trailing null byte doesn't count towards the total
    * ++str;
    */
    return str - buf;
}

/**
 * This function will fill a formatted string to buffer
 *
 * @buf  : the buffer to save formatted string
 * @size : the size of buffer
 * @fmt  : the format
 */
int qe_snprintf(char *buf, qe_size_t size, const char *fmt, ...)
{
    int n;
    va_list args;

    va_start(args, fmt);
    n = qe_vsnprintf(buf, size, fmt, args);
    va_end(args);

    return n;
}

/**
 * This function will fill a formatted string to buffer
 *
 * @buf     : the buffer to save formatted string
 * @arg_ptr : the arg_ptr
 * @format  : the format
 */
int qe_vsprintf(char *buf, const char *format, va_list arg_ptr)
{
    return qe_vsnprintf(buf, (qe_size_t) - 1, format, arg_ptr);
}
#endif


#if defined(_WIN32)
#include <time.h>
#include <Windows.h>

qe_u32 qe_time(void)
{
    time_t s;
    time(&s);
    return (qe_u32)s;
}

qe_u32 qe_time_ms(void)
{
    time_t s;
    SYSTEMTIME ms;
    
    time(&s);
    GetSystemTime(&ms);

    return (qe_u32)(s*1000 + ms.wMilliseconds);
}

void qe_sleep(qe_u32 ms)
{
    Sleep(ms);
}
#elif defined(__linux__)
#include <time.h>
#include <unistd.h>
#include <sys/time.h>
#include "qe_def.h"
qe_u32 qe_time(void)
{
    time_t s;
    time(&s);
    return (qe_u32)s;
}

qe_u32 qe_time_ms(void)
{
    struct timeval time;
    gettimeofday(&time, NULL);
    return (time.tv_sec * 1000 + time.tv_usec / 1000);
}

void qe_sleep(qe_u32 ms)
{
    sleep(ms);
}
#endif